package in

import (
	"errors"
	"fmt"
	"log"
	"strings"

	"github.com/360EntSecGroup-Skylar/excelize"
)

type XlsxBottle struct {
	Bottle
	SheetName string
}

func NewXlsxBottle(infoSchema string) (bottle *XlsxBottle, err error) {
	if !strings.HasPrefix(infoSchema, "xlsx://") {
		err = errors.New("not valid infoSchemal" + infoSchema)
		return
	}
	bottle = new(XlsxBottle)
	bottle.Data = infoSchema
	bottle.Engine = strings.SplitN(infoSchema, "xlsx://", 2)[1]
	bottle.IsFile = true
	bottle.IsDB = false
	bottle.Tp = "xlsx"
	return
}

func (bottle *XlsxBottle) GetName() string {
	return bottle.Data
}

func (bottle *XlsxBottle) Desc(oper *Oper) (keys S) {
	sheetName := oper.Name

	f, err := excelize.OpenFile(bottle.Engine.(string))
	if err != nil {
		log.Fatal("Open:", err)
		return
	}
	if sheetName == "" {
		for _, k := range f.GetSheetMap() {
			// println(k)
			keys = append(keys, k)
		}
		return
	}
	rows, err := f.Rows(sheetName)
	if err != nil {
		log.Fatal("xlsx read Row:", err)
	}
	for rows.Next() {
		if rows.Error() != nil {
			log.Fatal("Rows:", rows.Error())
			break
		}

		keys = rows.Columns()
		return

	}
	return
}

func (mdb *XlsxBottle) GetTp() string {
	return mdb.Tp
}

func (bottle *XlsxBottle) Query(oper *Oper) (datas Datas) {
	defer func() {
		if len(GlobalOperChannel) > 0 {
			<-GlobalOperChannel
		}
	}()
	GlobalOperChannel <- 0
	sheetName := oper.Name
	if sheetName == "" {
		sheetName = "Sheet1"
	}
	f, err := excelize.OpenFile(bottle.Engine.(string))
	if err != nil {
		log.Fatal(err)
		return
	}

	rows, err := f.Rows(sheetName)
	if err != nil {
		log.Fatal("xlsx read Row:", err)
	}
	// results := make([][]string, 0, 64)
	// offset := oper.Page * oper.Len
	filter := oper.Filter
	startAt := oper.Page * oper.Len
	endAt := startAt + oper.Len
	nowAt := 0
	co := 0
	var keys S
	for rows.Next() {

		if rows.Error() != nil {
			log.Fatal(rows.Error())
			break
		}
		if co == 0 {
			keys = rows.Columns()
			co++
			continue
		}

		row := rows.Columns()
		data := make(G)
		for no, v := range row {
			data[keys[no]] = v
		}
		if len(filter) > 0 {
			ifJump := false
			// ColorD(filter)
			for fK, fV := range filter {
				if tryMatch, ok := data[fK]; !ok || !strings.Contains(fmt.Sprint(tryMatch), fmt.Sprint(fV)) {
					ifJump = true
					break
				} else {
					// ColorL("match :", fK, fV)
				}
			}

			if ifJump {
				co++
				continue
			}
		}
		nowAt++
		if nowAt >= startAt && nowAt < endAt {
			datas = append(datas, data)
		}
		if nowAt >= endAt {
			break
		}

		co++
	}
	if !bottle.NoCached {
		SaveInCache(bottle.Data+"/"+oper.Name, datas)
	}
	return
}
